From: Aron Xu <aron@debian.org>
Date: Mon, 13 Feb 2012 15:16:04 +0800
Subject: quit timer

---
 nc.1     |    5 +++++
 netcat.c |   38 +++++++++++++++++++++++++++++++++-----
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/nc.1 b/nc.1
index af44976..0d92b74 100644
--- a/nc.1
+++ b/nc.1
@@ -40,6 +40,7 @@
 .Op Fl O Ar length
 .Op Fl P Ar proxy_username
 .Op Fl p Ar source_port
+.Op Fl q Ar seconds
 .Op Fl s Ar source
 .Op Fl T Ar toskeyword
 .Op Fl V Ar rtable
@@ -148,6 +149,10 @@ Proxy authentication is only supported for HTTP CONNECT proxies at present.
 Specifies the source port
 .Nm
 should use, subject to privilege restrictions and availability.
+.It Fl q Ar seconds
+after EOF on stdin, wait the specified number of seconds and then quit. If
+.Ar seconds
+is negative, wait forever.
 .It Fl r
 Specifies that source and/or destination ports should be chosen randomly
 instead of sequentially within a range or in the order that the system
diff --git a/netcat.c b/netcat.c
index 4f4d2bf..29ecf1a 100644
--- a/netcat.c
+++ b/netcat.c
@@ -86,6 +86,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include <poll.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -120,6 +121,7 @@ int	lflag;					/* Bind to local port */
 int	nflag;					/* Don't do name look up */
 char   *Pflag;					/* Proxy username */
 char   *pflag;					/* Localport flag */
+int     qflag = 0;                             /* Quit after some secs */
 int	rflag;					/* Random ports flag */
 char   *sflag;					/* Source Address */
 int	tflag;					/* Telnet Emulation */
@@ -158,6 +160,7 @@ void	usage(int);
 
 static int connect_with_timeout(int fd, const struct sockaddr *sa,
         socklen_t salen, int ctimeout);
+static void quit();
 
 int
 main(int argc, char *argv[])
@@ -181,7 +184,7 @@ main(int argc, char *argv[])
 	sv = NULL;
 
 	while ((ch = getopt(argc, argv,
-	    "46CDdhI:i:jklnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
+	    "46CDdhI:i:jklnO:P:p:q:rSs:tT:UuV:vw:X:x:z")) != -1) {
 		switch (ch) {
 		case '4':
 			family = AF_INET;
@@ -235,6 +238,11 @@ main(int argc, char *argv[])
 		case 'p':
 			pflag = optarg;
 			break;
+                case 'q':
+			qflag = strtonum(optarg, INT_MIN, INT_MAX, &errstr);
+			if (errstr)
+				errx(1, "quit timer %s: %s", errstr, optarg);
+			break;
 		case 'r':
 			rflag = 1;
 			break;
@@ -924,9 +932,18 @@ readwrite(int nfd)
 			}
 			else if (pfd[1].revents & POLLHUP) {
 			shutdown_wr:
+			/* if the user asked to exit on EOF, do it */
+			if (qflag == 0) {
 				shutdown(nfd, SHUT_WR);
-				pfd[1].fd = -1;
-				pfd[1].events = 0;
+				close(wfd);
+			}
+			/* if user asked to die after a while, arrange for it */
+			if (qflag > 0) {
+				signal(SIGALRM, quit);
+				alarm(qflag);
+			}
+			pfd[1].fd = -1;
+			pfd[1].events = 0;
 			}
 		}
 	}
@@ -1164,6 +1181,7 @@ help(void)
 	\t-O length	TCP send buffer length\n\
 	\t-P proxyuser\tUsername for proxy authentication\n\
 	\t-p port\t	Specify local port for remote connects\n\
+        \t-q secs\t	quit after EOF on stdin and delay of secs\n\
 	\t-r		Randomize remote ports\n\
 	\t-S		Enable the TCP MD5 signature option\n\
 	\t-s addr\t	Local source address\n\
@@ -1186,9 +1204,19 @@ usage(int ret)
 {
 	fprintf(stderr,
 	    "usage: nc [-46CDdhjklnrStUuvz] [-I length] [-i interval] [-O length]\n"
-	    "\t  [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n"
-	    "\t  [-V rtable] [-w timeout] [-X proxy_protocol]\n"
+	    "\t  [-P proxy_username] [-p source_port] [-q seconds] [-s source]\n"
+	    "\t  [-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol]\n"
 	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
 	if (ret)
 		exit(1);
 }
+
+/*
+ * quit()
+ * handler for a "-q" timeout (exit 0 instead of 1)
+ */
+static void quit()
+{
+        /* XXX: should explicitly close fds here */
+        exit(0);
+}
-- 
